﻿using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;

namespace UnityX
{
    /// <summary>
    /// 简单快速的播放声音
    /// </summary>
    public static class Audio
    {
        private class MyMonoBehaviour : MonoBehaviour
        {
        }
        private static Dictionary<string, AudioClip> audioClips = new Dictionary<string, AudioClip>();
        private static List<AudioSource> audioSources = new List<AudioSource>();
        private static MyMonoBehaviour monoBehaviour;
        static Audio()
        {
            GameObject gameObject = new GameObject("_X_Audio_X_");
            gameObject.hideFlags = HideFlags.HideInHierarchy;
            Object.DontDestroyOnLoad(gameObject);
            monoBehaviour = gameObject.AddComponent<MyMonoBehaviour>();
            for (int i = 0; i < 3; i++)
            {
                CreateAudioSource();
            }
        }
        private static AudioSource CreateAudioSource()
        {
            GameObject gameObject = new GameObject("_X_Item_X_");
            gameObject.transform.SetParent(monoBehaviour.transform);
            AudioSource audioSource = gameObject.AddComponent<AudioSource>();
            audioSource.playOnAwake = false;
            audioSources.Add(audioSource);
            return audioSource;
        }

        /// <summary>
        /// 加载Resources资源包里面的声音文件
        /// </summary>
        /// <param name="name">文件名</param>
        public static void LoadResourcesFile(string name)
        {
            AudioClip clip = Resources.Load<AudioClip>(name);
            if (clip == null)
            {
                Debug.LogError("资源文件夹下未找到声音文件! name=" + name);
                return;
            }
            audioClips.Add(clip.name, clip);
        }
        /// <summary>
        /// 加载Resources资源目录里面的所有声音文件
        /// </summary>
        /// <param name="name">目录名</param>
        public static void LoadResourcesDirectory(string name)
        {
            AudioClip[] clips = Resources.LoadAll<AudioClip>(name);
            if (clips.Length == 0)
            {
                Debug.LogError("资源文件夹下未找到声音文件! name=" + name);
                return;
            }
            foreach (var item in clips)
            {
                audioClips.Add(item.name, item);
            }
        }

        // 加载本地声音文件
        private static IEnumerator LoadAsync(string path, AudioType audioType)
        {
            using (UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(
                @"file://" + path.Replace(" ", "%20").Replace("+", "%2B").Replace("=", "%3D").Replace("#", "%23").Replace("&", "%26"),
                audioType))
            {
                yield return www.SendWebRequest();
#if UNITY_2020_3_OR_NEWER
                if (www.result == UnityWebRequest.Result.Success)
#else
                if (www.error == null)
#endif
                {
                    string name = Path.GetFileNameWithoutExtension(path);
                    if (!audioClips.ContainsKey(name))
                    {
                        AudioClip audioClip = DownloadHandlerAudioClip.GetContent(www);
                        if (audioClip != null)
                        {
                            audioClip.name = name;
                            audioClips.Add(audioClip.name, audioClip);
                        }
                        else
                        {
                            Debug.LogError("声音加载出错! path=" + path);
                        }
                    }
                    else
                    {
                        Debug.LogWarning("声音文件已经存在! path=" + path);
                    }
                }
                else
                {
                    Debug.LogError("声音加载出错! error=" + www.error);
                }
            }
        }
        /// <summary>
        /// 加载本地声音文件
        /// </summary>
        /// <param name="path">文件路径</param>
        public static void LoadLocalFile(string path)
        {
            if (!File.Exists(path))
            {
                Debug.LogError("本地声音文件不存在! path=" + path);
                return;
            }
            string extension = Path.GetExtension(path).ToLower();
            switch (extension)
            {
                case ".wav":
                    monoBehaviour.StartCoroutine(LoadAsync(path, AudioType.WAV));
                    break;
                case ".ogg":
                    monoBehaviour.StartCoroutine(LoadAsync(path, AudioType.OGGVORBIS));
                    break;
                case ".mp3":
                    monoBehaviour.StartCoroutine(LoadAsync(path, AudioType.MPEG));
                    break;
                default:
                    //Debug.LogError("声音格式不支持! path=" + path);
                    break;
            }
        }
        /// <summary>
        /// 加载本地目录里面的所有声音文件
        /// </summary>
        /// <param name="path">目录路径</param>
        public static void LoadLocalDirectory(string path)
        {
            if (!Directory.Exists(path))
            {
                Debug.LogError("本地声音文件目录不存在! path=" + path);
                return;
            }
            DirectoryInfo DirInfo = new DirectoryInfo(path);
            FileInfo[] files = DirInfo.GetFiles("*", SearchOption.AllDirectories);
            foreach (FileInfo fi in files)
            {
                LoadLocalFile(fi.FullName);
            }
        }

        /// <summary>
        /// 添加一个声音到播放系统
        /// </summary>
        /// <param name="audioClip"></param>
        public static void Add(AudioClip audioClip)
        {
            if (!audioClips.ContainsKey(audioClip.name))
            {
                audioClips.Add(audioClip.name, audioClip);
            }
            else
            {
                Debug.LogWarning("声音文件已经存在，重复添加！ name=" + audioClip.name);
            }
        }

        /// <summary>
        /// 释放全部加载的声音文件
        /// </summary>
        public static void ReleaseAll()
        {
            audioSources.Clear();
            audioClips.Clear();
        }

        /// <summary>
        /// 播放2D声音
        /// </summary>
        /// <param name="name">名字</param>
        public static void Play(string name)
        {
            Play(name, false, 1, 1);
        }
        /// <summary>
        /// 播放2D声音
        /// </summary>
        /// <param name="name">名字</param>
        /// <param name="loop">是否循环播放</param>
        public static void Play(string name, bool loop)
        {
            Play(name, loop, 1, 1);
        }
        /// <summary>
        /// 播放2D声音
        /// </summary>
        /// <param name="name">名字</param>
        /// <param name="loop">是否循环播放</param>
        /// <param name="speed">播放速度</param>
        public static void Play(string name, bool loop, float speed)
        {
            Play(name, loop, speed, 1);
        }
        /// <summary>
        /// 播放2D声音
        /// </summary>
        /// <param name="name">名字</param>
        /// <param name="loop">是否循环播放</param>
        /// <param name="speed">播放速度</param>
        /// <param name="volume">音量</param>
        public static void Play(string name, bool loop, float speed, float volume)
        {
            if (!audioClips.ContainsKey(name))
            {
                AudioClip clip = Resources.Load<AudioClip>("Audio/" + name);
                if (clip == null)
                {
                    Debug.LogError("声音未找到！ name=" + name);
                    return;
                }
                audioClips.Add(clip.name, clip);
            }

            foreach (AudioSource item in audioSources)
            {
                if (!item.isPlaying)
                {
                    item.spatialBlend = 0;
                    item.pitch = speed;
                    item.loop = loop;
                    item.volume = volume;
                    item.clip = audioClips[name];
                    item.Play();
                    return;
                }
            }
            AudioSource audioSource = CreateAudioSource();
            audioSource.spatialBlend = 0;
            audioSource.pitch = speed;
            audioSource.loop = loop;
            audioSource.volume = volume;
            audioSource.clip = audioClips[name];
            audioSource.Play();
        }

        /// <summary>
        /// 播放3D声音
        /// </summary>
        /// <param name="name">名字</param>
        /// <param name="position">空间位置</param>
        public static void Play3D(string name, Vector3 position)
        {
            Play3D(name, position, false, 1, 1);
        }
        /// <summary>
        /// 播放3D声音
        /// </summary>
        /// <param name="name">名字</param>
        /// <param name="position">空间位置</param>
        /// <param name="loop">是否循环播放</param>
        public static void Play3D(string name, Vector3 position, bool loop)
        {
            Play3D(name, position, loop, 1, 1);
        }
        /// <summary>
        /// 播放3D声音
        /// </summary>
        /// <param name="name">名字</param>
        /// <param name="position">空间位置</param>
        /// <param name="loop">是否循环播放</param>
        /// <param name="speed">播放速度</param>
        public static void Play3D(string name, Vector3 position, bool loop, float speed)
        {
            Play3D(name, position, loop, speed, 1);
        }
        /// <summary>
        /// 播放3D声音
        /// </summary>
        /// <param name="name">名字</param>
        /// <param name="position">空间位置</param>
        /// <param name="loop">是否循环播放</param>
        /// <param name="speed">播放速度</param>
        /// <param name="volume">音量</param>
        public static void Play3D(string name, Vector3 position, bool loop, float speed, float volume)
        {
            if (!audioClips.ContainsKey(name))
            {
                AudioClip clip = Resources.Load<AudioClip>("Audio/" + name);
                if (clip == null)
                {
                    Debug.LogError("声音未找到！ name=" + name);
                    return;
                }
                audioClips.Add(clip.name, clip);
            }

            foreach (AudioSource item in audioSources)
            {
                if (!item.isPlaying)
                {
                    item.transform.position = position;
                    item.spatialBlend = 1;
                    item.loop = loop;
                    item.pitch = speed;
                    item.volume = volume;
                    item.clip = audioClips[name];
                    item.Play();
                    return;
                }
            }
            AudioSource audioSource = CreateAudioSource();
            audioSource.transform.position = position;
            audioSource.spatialBlend = 1;
            audioSource.loop = loop;
            audioSource.pitch = speed;
            audioSource.volume = volume;
            audioSource.clip = audioClips[name];
            audioSource.Play();
        }
        /// <summary>
        /// 停止正在播放的声音
        /// </summary>
        /// <param name="name"></param>
        public static void Stop(string name)
        {
            foreach (AudioSource item in audioSources)
            {
                if (item != null && item.clip != null && item.clip.name == name)
                {
                    item.Stop();
                }
            }
        }
        /// <summary>
        /// 停止全部播放的声音
        /// </summary>
        public static void StopAll()
        {
            foreach (AudioSource item in audioSources)
            {
                if (item != null && item.isPlaying)
                {
                    item.Stop();
                }
            }
        }
    }
}